package com.quectel.mobile.controller.mobileuser;

import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.thirdconfig.ThirdPlatformConfigBusiness;
import com.quectel.constant.SandboxConfig;
import com.quectel.constant.core.officialaccount.OfficialAccountsConstants;
import com.quectel.constant.global.SMSConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.car.dto.CarDto;
import com.quectel.core.module.car.service.CarService;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.mobileuser.dto.MobileUserDto;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.core.module.officialaccounts.dto.OfficialAccountsBindingDto;
import com.quectel.core.module.officialaccounts.service.OfficialAccountsBindingService;
import com.quectel.core.module.partybuilding.service.PartyPersonService;
import com.quectel.core.module.thirdconfig.dto.item.WechatOfficial;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.mobile.controller.BaseController;
import com.quectel.mobile.interceptor.LoginMobileUserSession;
import com.quectel.mobile.util.SessionHolder;
import com.quectel.mobile.util.SmsCompnent;
import com.quectel.mobile.vo.mobileuser.MobileBaseInfoWithMobileVo;
import com.quectel.mobile.vo.mobileuser.MobileUserBaseInfoVo;
import com.quectel.mobile.vo.mobileuser.login.ChangeSessionVo;
import com.quectel.mobile.vo.mobileuser.login.JSAPILoginVo;
import com.quectel.mobile.vo.mobileuser.login.SendVerCodeVo;
import com.quectel.sdk.officialaccounts.OfficialAccountsUtils;
import com.quectel.sdk.officialaccounts.model.WechatJSAPIUserInfo;
import com.quectel.sys.module.sys.dto.SysTenantDto;
import com.quectel.sys.module.sys.service.SysTenantService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.security.TokenUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 */
@RestController
@RequestMapping("mobileUser")
@Tag(name = "MobileUserController", description = "用户登录修改等相关的api")
public class MobileUserController extends BaseController {
    @DubboReference
    private VillageService villageService;
    @DubboReference
    private MobileUserService mobileUserService;
    @DubboReference
    private HouseholdService householdService;
    @DubboReference
    private OfficialAccountsBindingService officialAccountsBindingService;
    @DubboReference
    private SysTenantService sysTenantService;
    @DubboReference
    private CarService carService;
    @DubboReference
    private PartyPersonService partyPersonService;

    @Autowired
    private SmsCompnent smsCompnent;

    @Autowired
    private ThirdPlatformConfigBusiness thirdPlatformConfigBusiness;

    @PostMapping("JSAPI/login")
    @Operation(summary = "JSAPI登录接口,获取token,后续请求需要在请求头中加入token")
    public Response<LoginMobileUserSession> JSAPILogin(@RequestBody JSAPILoginVo loginVo) {

        logger.debug("微信用户获取openId，请求参数：code=" + JacksonUtils.toJsonString(loginVo));

        SysTenantDto sysTenantDto = sysTenantService.selectOneByCode(loginVo.getTenantCode());
        if (sysTenantDto == null) {
            return Response.error("链接错误请检查");
        }

        LoginMobileUserSession loginMobileUserSession = new LoginMobileUserSession();
        loginMobileUserSession.setLoginType(SystemConstants.LoginType.JS_API.getType());
        loginMobileUserSession.setTenantId(sysTenantDto.getId());
        loginMobileUserSession.setOfficialAccountsType(loginVo.getOfficialAccountsType());

        String openId = null;
        if (SystemConstants.OFFICIAL_ACCOUNTS_PLATFORM_WX.equals(loginVo.getOfficialAccountsType())) {
            WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(sysTenantDto.getId());

            if (wechatOfficialConfig == null) {
                throw new CheckErrorException("公众号没有配置");
            }
            loginMobileUserSession.setAppId(wechatOfficialConfig.getAppId());

            // 查询配置 获取微信用户唯一id
            openId = OfficialAccountsUtils.getWxJsApiUserId(wechatOfficialConfig.getAppId(),
                    wechatOfficialConfig.getAppSecret(), loginVo.getCode());
        } else {
            // 获取支付宝的用户id
            openId = OfficialAccountsUtils.getZfbUserId(
                    SandboxConfig.AliPaySandbox.APP_ID,
                    SandboxConfig.AliPaySandbox.ALI_PUBLIC_KEY,
                    SandboxConfig.AliPaySandbox.SELF_PRIVATE_KEY,
                    loginVo.getCode()
            );
        }

        if (StringUtils.isBlank(openId)) {
            return Response.error("无法获取用户信息");
        }

        loginMobileUserSession.setOpenId(openId);
        loginMobileUserSession.setToken(TokenUtils.genRandomToken());

        //查看是否有绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginVo.getOfficialAccountsType(),
                loginVo.getAppId(),
                openId,
                OfficialAccountsConstants.PERSON_TYPE_MOBILE_USER
        );
        if (officialAccountsBindingDto != null) {
            //已绑定
            MobileUserDto mobileUserDto = mobileUserService.selectById(officialAccountsBindingDto.getPersonId());
            loginMobileUserSession.setMobileUser(mobileUserDto);

        }

        return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    @GetMapping("getWxJSSDKConfig")
    @Operation(summary = "微信配置")
    public Response<Object> getWxJSSDKConfig(@RequestParam String currentPageUrl) {

        LoginMobileUserSession loginMobileUserSession = SessionHolder.getLoginMobileUserSession();

        WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(loginMobileUserSession.getTenantId());
        if (wechatOfficialConfig == null) {
            throw new CheckErrorException("公众号没有配置");
        }

        Map<String, String> wxJSSDKConfig = OfficialAccountsUtils.getWxJSSDKConfig(wechatOfficialConfig.getAppId(), wechatOfficialConfig.getAppSecret(), currentPageUrl);

        return Response.ok().wrap(wxJSSDKConfig);

    }

    @PostMapping("logout")
    @Operation(summary = "退出")
    public Response<Object> logout() {
        LoginMobileUserSession session = SessionHolder.getLoginMobileUserSession();
        if (session != null) {

            SessionHolder.logout();

            //解除关系
            OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                    session.getOfficialAccountsType(),
                    session.getAppId(),
                    session.getOpenId(),
                    OfficialAccountsConstants.PERSON_TYPE_MOBILE_USER
            );
            if (officialAccountsBindingDto != null) {
                officialAccountsBindingService.deleteById(officialAccountsBindingDto.getId());
            }


        }
        return Response.ok();
    }

    /**
     * 前端切换小区，后台查询该小区下的household信息并替换
     *
     * @param changeSessionVo
     * @return
     */
    @PostMapping("changeSession")
    @Operation(summary = "根据小区id更换用户session")
    public Response<LoginMobileUserSession> changeSession(@RequestBody ChangeSessionVo changeSessionVo) {

        LoginMobileUserSession loginMobileUserSession = SessionHolder.getLoginMobileUserSession();
        //当前前端选择的小区
        loginMobileUserSession.setCurrentVillageId(changeSessionVo.getVillageId());

        if (loginMobileUserSession.getMobileUser() == null) {
            //没有认证过
            return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
        }
        HouseholdDto houseHoldDto = householdService
                .selectByVillageIdAndMobile(changeSessionVo.getVillageId(), loginMobileUserSession.getMobileUser().getMobile());
        loginMobileUserSession.setCurrentHousehold(houseHoldDto);

        return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 发送验证码
     *
     * @return
     */
    @PostMapping("sendBindingMsgCode")
    @Operation(summary = "发送绑定公众号验证码")
    public Response<Object> sendBindingMsgCode(@RequestBody SendVerCodeVo sendVerCodeVo) {

        String code = smsCompnent.sendVerCode(SessionHolder.getLoginMobileUserSession().getTenantId(), sendVerCodeVo.getMobile(), SMSConstants.VerCodeType.OFFICIAL_ACCOUNTS_BINDING);
        if (code == null) {
            return Response.error("发送验证码失败");
        }

        return Response.ok().wrap(thirdPlatformConfigBusiness.smsMockEnable(SessionHolder.getLoginMobileUserSession().getTenantId()) ? code : null);
    }

    /**
     * 设置个人信息
     *
     * @return
     */
    @PostMapping("setMyBaseInfo")
    @Operation(summary = "第一次设置个人信息")
    public Response<LoginMobileUserSession> setMyBaseInfo(@RequestBody MobileBaseInfoWithMobileVo baseInfoWithMobile) {

        boolean isLegal = smsCompnent.checkVerCode(baseInfoWithMobile.getMobile(), baseInfoWithMobile.getVerCode(), SMSConstants.VerCodeType.OFFICIAL_ACCOUNTS_BINDING);
        if (!isLegal) {
            smsCompnent.invalidVerCode(baseInfoWithMobile.getMobile(), SMSConstants.VerCodeType.OFFICIAL_ACCOUNTS_BINDING);
            return Response.error("您输入验证码不正确或者不在有效期内,请重新发送");
        }

        Date date = new Date();

        LoginMobileUserSession loginMobileUserSession = SessionHolder.getLoginMobileUserSession();

        MobileUserDto mobileUserDto = mobileUserService.selectByMobile(baseInfoWithMobile.getMobile());

        if (mobileUserDto == null) {
            mobileUserDto = new MobileUserDto();

            CopyUtils.copyTo(baseInfoWithMobile, mobileUserDto, true);
            mobileUserDto.setCreateTime(date);

            if (SystemConstants.OFFICIAL_ACCOUNTS_PLATFORM_WX.equals(loginMobileUserSession.getOfficialAccountsType())) {

                WechatOfficial wechatOfficialConfig = thirdPlatformConfigBusiness.getWechatOfficialConfig(loginMobileUserSession.getTenantId());
                //查询头像
                if (wechatOfficialConfig != null) {
                    WechatJSAPIUserInfo wxUserInfoDetail = OfficialAccountsUtils.getWxUserInfoDetail(wechatOfficialConfig.getAppId(), wechatOfficialConfig.getAppSecret(), loginMobileUserSession.getOpenId());
                    if (wxUserInfoDetail != null) {
                        if (StringUtils.isNotBlank(wxUserInfoDetail.getHeadimgurl())) {
                            mobileUserDto.setHeadImg(wxUserInfoDetail.getHeadimgurl());
                        }
                        if (StringUtils.isNotBlank(wxUserInfoDetail.getNickname())) {
                            mobileUserDto.setNickname(wxUserInfoDetail.getNickname());
                        }
                    }
                }
            }

            Long id = mobileUserService.save(mobileUserDto);
            mobileUserDto.setId(id);
        } else {
            //第二次需要更新
            CopyUtils.copyTo(baseInfoWithMobile, mobileUserDto, true);
            mobileUserService.updateById(mobileUserDto);
        }
        //是否绑定
        OfficialAccountsBindingDto officialAccountsBindingDto = officialAccountsBindingService.selectBy(
                loginMobileUserSession.getOfficialAccountsType(),
                loginMobileUserSession.getAppId(),
                loginMobileUserSession.getOpenId(),
                OfficialAccountsConstants.PERSON_TYPE_MOBILE_USER
        );
        if (officialAccountsBindingDto == null) {
            //没有绑定
            officialAccountsBindingDto = new OfficialAccountsBindingDto();
            officialAccountsBindingDto.setType(loginMobileUserSession.getOfficialAccountsType());
            officialAccountsBindingDto.setAppId(loginMobileUserSession.getAppId());
            officialAccountsBindingDto.setOpenId(loginMobileUserSession.getOpenId());
            officialAccountsBindingDto.setPersonType(OfficialAccountsConstants.PERSON_TYPE_MOBILE_USER);
            officialAccountsBindingDto.setPersonId(mobileUserDto.getId());
            officialAccountsBindingDto.setCreateTime(date);
            officialAccountsBindingService.save(officialAccountsBindingDto);
        } else {
            if (!Objects.equals(officialAccountsBindingDto.getPersonId(), mobileUserDto.getId())) {
                //有绑定绑定的不是该用户需用重新绑定
                officialAccountsBindingDto.setPersonId(mobileUserDto.getId());
                officialAccountsBindingService.updateById(officialAccountsBindingDto);
            }
        }

        loginMobileUserSession.setMobileUser(mobileUserDto);

        return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 发送验证码
     *
     * @return
     */
    @PostMapping("sendUpdateMobileMsgCode")
    @Operation(summary = "发送修改手机号验证码")
    public Response<Object> sendUpdatePassMsgCode(@RequestBody SendVerCodeVo sendVerCodeVo) {

        MobileUserDto dbValue = mobileUserService.selectByMobile(sendVerCodeVo.getMobile());

        if (dbValue != null && !Objects.equals(dbValue.getId(), SessionHolder.getLoginMobileUserSession().getMobileUser().getId())) {
            return Response.error("您修改的手机号被占用");
        }

        String code = smsCompnent.sendVerCode(SessionHolder.getLoginMobileUserSession().getTenantId(), sendVerCodeVo.getMobile(), SMSConstants.VerCodeType.EDIT_MOBILE);
        if (code == null) {
            return Response.error("发送验证码失败");
        }
        return Response.ok().wrap(thirdPlatformConfigBusiness.smsMockEnable(SessionHolder.getLoginMobileUserSession().getTenantId()) ? code : null);
    }

    /**
     * 修改手机
     * 通过oldMobile，查询住户和车辆信息，并更新为新的手机号
     *
     * @return
     */
    @PostMapping("editMyMobile")
    @Operation(summary = "修改手机")
    public Response<LoginMobileUserSession> editMobile(@RequestBody MobileBaseInfoWithMobileVo mobileBaseInfoWithMobileVo) {

        LoginMobileUserSession loginMobileUserSession = SessionHolder.getLoginMobileUserSession();

        assert loginMobileUserSession != null;
        String oldMobile = loginMobileUserSession.getMobileUser().getMobile();

        MobileUserDto dbValue = mobileUserService.selectByMobile(mobileBaseInfoWithMobileVo.getMobile());
        if (dbValue != null && !Objects.equals(dbValue.getId(), loginMobileUserSession.getMobileUser().getId())) {
            return Response.error("您修改的手机号被占用");
        }

        boolean isLegal = smsCompnent.checkVerCode(mobileBaseInfoWithMobileVo.getMobile(), mobileBaseInfoWithMobileVo.getVerCode(), SMSConstants.VerCodeType.EDIT_MOBILE);
        if (!isLegal) {
            smsCompnent.invalidVerCode(mobileBaseInfoWithMobileVo.getMobile(), SMSConstants.VerCodeType.EDIT_MOBILE);
            return Response.error("您输入验证码不正确或者不在有效期内,请重新发送");
        }
        MobileUserDto mobileUserDto = new MobileUserDto();
        mobileUserDto.setId(SessionHolder.getLoginMobileUserSession().getMobileUser().getId());
        mobileUserDto.setMobile(mobileBaseInfoWithMobileVo.getMobile());
        mobileUserService.editMobile(mobileUserDto);

        // 通过oldMobile 查询住户车辆信息，更新为新的手机号
        List<HouseholdDto> householdDtos = householdService.selectByMobile(oldMobile);
        if (CollectionUtils.isNotEmpty(householdDtos)) {
            for (HouseholdDto household : householdDtos) {
                HouseholdDto updately = new HouseholdDto();
                updately.setId(household.getId());
                updately.setMobile(mobileBaseInfoWithMobileVo.getMobile());
                updately.setEditTime(new Date());
                householdService.updateById(updately);
            }
        }

        List<CarDto> carDtos = carService.selectByMobile(oldMobile);
        if (CollectionUtils.isNotEmpty(carDtos)) {
            for (CarDto car : carDtos) {
                CarDto updately = new CarDto();
                updately.setId(car.getId());
                updately.setOwnerMobile(mobileBaseInfoWithMobileVo.getMobile());
                updately.setEditTime(new Date());
                carService.updateById(updately);
            }
        }

        //重新覆盖session
        loginMobileUserSession.setMobileUser(mobileUserService.selectById(loginMobileUserSession.getMobileUser().getId()));

        return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 完善个人信息
     *
     * @return
     */
    @PostMapping("editPersonalInfo")
    @Operation(summary = "完善个人信息 头像性别（不包含手机号）")
    public Response<LoginMobileUserSession> editMyBaseInfo(@RequestBody MobileUserBaseInfoVo mobileUserBaseInfoVo) {

        LoginMobileUserSession loginMobileUserSession = SessionHolder.getLoginMobileUserSession();


        //覆盖跳过空置
        MobileUserDto mobileUserDto = CopyUtils.copyObj(mobileUserBaseInfoVo, MobileUserDto.class);
        mobileUserDto.setId(loginMobileUserSession.getMobileUser().getId());
        mobileUserService.updateById(mobileUserDto);

        //重新覆盖session
        loginMobileUserSession.setMobileUser(mobileUserService.selectById(loginMobileUserSession.getMobileUser().getId()));

        return Response.<LoginMobileUserSession>ok().wrap(SessionHolder.resetLoginMobileUserSession(loginMobileUserSession));
    }

    /**
     * 得到租户下小区
     *
     * @return
     */
    @GetMapping("getVillages")
    @Operation(summary = "得到租户下小区")
    public Response<List<VillageDto>> getVillages() {
        Map<String, Object> params = new HashMap<>();

        params.put(LambdaUtil.getFieldName(VillageDto::getTenantId), SessionHolder.getLoginMobileUserSession().getTenantId());
        //绑定部分社区
        return Response.<List<VillageDto>>ok().wrap(villageService.queryList(params));
    }

    /**
     * 得到我已经认证的小区
     *
     * @return
     */
    @GetMapping("getMyVillages")
    @Operation(summary = "得到我已经认证的小区")
    public Response<List<VillageDto>> getMyVillages() {
        if (SessionHolder.getLoginMobileUserSession() == null || SessionHolder.getLoginMobileUserSession().getMobileUser() == null) {
            return Response.<List<VillageDto>>ok().wrap(new ArrayList<>());
        }
        List<HouseholdDto> list = householdService.selectByMobile(SessionHolder.getLoginMobileUserSession().getMobileUser().getMobile());
        return Response.<List<VillageDto>>ok().wrap(
                list
                        .stream()
                        .filter(v -> Objects.equals(SessionHolder.getLoginMobileUserSession().getTenantId(), v.getTenantId()))
                        .map(v -> villageService.selectCacheById(v.getVillageId()))
                        .collect(Collectors.toList())
        );
    }

}
